/**
 * @file	bleuart_service.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "sdk_config.h"
#include "att.h"
#include "log.h"
#include "OSAL.h"
#include "error.h"
#include "gatt.h"
#include "linkdb.h"
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "global_config.h"
#include "bleuart_service.h"
#include "multi_role.h"
#include "at_command.h"
#include "ll_def.h"


///< Rawpass GATT Profile Service UUID
uint8 bleuart_ServiceUUID[ATT_UUID_SIZE] =
{
    //0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    //0x00, 0x10, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00
	0xF0, 0xFF
};

///< Characteristic tx uuid
uint8 bleuart_TxCharUUID[ATT_UUID_SIZE] =
{ 
	//0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    //0x00, 0x10, 0x00, 0x00, 0xF1, 0xFF, 0x00, 0x00
	0xF1, 0xFF
};
///< Characteristic rx uuid
uint8 bleuart_RxCharUUID[ATT_UUID_SIZE] =
{ 
	//0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
    //0x00, 0x10, 0x00, 0x00, 0xF2, 0xFF, 0x00, 0x00
	0xF2, 0xFF
};
///< Characteristic rx uuid
uint8 bleuart_AT_UUID[ATT_UUID_SIZE] =
{ 
   //0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 
   //0x00, 0x10, 0x00, 0x00, 0xF3, 0xFF, 0x00, 0x00
   0xF3, 0xFF
};

/*********************************************************************
 * LOCAL VARIABLES
 */
//static bleuart_ProfileChangeCB_t bleuart_AppCBs = NULL;

/*********************************************************************
 * Profile Attributes - variables
 */
///< Profile Service attribute
static  gattAttrType_t bleuart_Service = { ATT_BT_UUID_SIZE, bleuart_ServiceUUID };

///< Profile Characteristic 1 Properties
static uint8 bleuart_TxCharProps = GATT_PROP_NOTIFY;

///< Characteristic 1 Value
static uint8 bleuart_TxCharValue = 0;

///< Simple Profile Characteristic 1 User Description
static gattCharCfg_t bleuart_TxCCCD[GATT_MAX_NUM_CONN];

///< Profile Characteristic 2 Properties
static uint8 bleuart_RxCharProps = GATT_PROP_WRITE_NO_RSP;

///< Characteristic 2 Value
static uint8 bleuart_RxCharValue[RAWPASS_RX_BUFF_SIZE];
///< Profile Characteristic 1 Properties
static uint8 bleuart_AT = GATT_PROP_NOTIFY|GATT_PROP_WRITE_NO_RSP;
///< Characteristic 1 Value
static uint8 bleuart_AT_CharValue = 0;

/*********************************************************************
 * Profile Attributes - Table
 */
gattAttribute_t bleuart_ProfileAttrTbl[] = 
{
	///< Simple Profile Service
	{
		{ ATT_BT_UUID_SIZE, primaryServiceUUID }, 	/* type */
		GATT_PERMIT_READ,                         	/* permissions */
		0,                                        	/* handle */
		(uint8 *)&bleuart_Service            		/* pValue */
	},

	///< Characteristic 1 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&bleuart_TxCharProps
	},

	///< Characteristic Value 1
	{
		{ ATT_BT_UUID_SIZE, bleuart_TxCharUUID },
		0,
		0,
		(uint8 *)&bleuart_TxCharValue
	},

	///< Characteristic 1 User Description
	{
		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		(uint8*)bleuart_TxCCCD
	},

	///< Characteristic 2 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ,
		0,
		&bleuart_RxCharProps
	},

	///< Characteristic Value 2
	{
		{ ATT_BT_UUID_SIZE, bleuart_RxCharUUID },
		GATT_PERMIT_WRITE,
		0,
		&bleuart_RxCharValue[0]
	},
		///< Characteristic 3 Declaration
	{
		{ ATT_BT_UUID_SIZE, characterUUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		&bleuart_AT
	},
	///< Characteristic Value 3
	{
		{ ATT_BT_UUID_SIZE, bleuart_AT_UUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		(uint8 *)&bleuart_AT_CharValue
	},

	///< Characteristic 3 User Description
	{
		{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
		GATT_PERMIT_READ|GATT_PERMIT_WRITE,
		0,
		(uint8*)bleuart_TxCCCD
	}
};

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static bStatus_t bleuart_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset );
static void bleuart_HandleConnStatusCB( uint16 connHandle, uint8 changeType );

/*********************************************************************
 * PROFILE CALLBACKS
 */
CONST gattServiceCBs_t bleuart_ProfileCBs =
{
	NULL,
	bleuart_WriteAttrCB, // Write callback function pointer
	NULL                 // Authorization callback function pointer
};

/**
 * @fn      bleuart_AddService
 * @brief   Peripheral initialization
 * @param   cb
 * @return  none
 */
bStatus_t bleuart_AddService(void)
{
	uint8 status = SUCCESS;

	// Register with Link DB to receive link status change callback
	VOID linkDB_Register( bleuart_HandleConnStatusCB  );  

    GATTServApp_InitCharCfg( INVALID_CONNHANDLE, bleuart_TxCCCD );
	// Register GATT attribute list and CBs with GATT Server App
	status = GATTServApp_RegisterService( bleuart_ProfileAttrTbl, 
										  GATT_NUM_ATTRS( bleuart_ProfileAttrTbl ),
										  &bleuart_ProfileCBs );
	//bleuart_AppCBs = cb;
	return ( status );
}

void ble_service_init(void)
{
	if(user_data.service.flag == 0)
	{
		bleuart_Service.len = ATT_BT_UUID_SIZE;
		masterLinkUUIDLen = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;

		bleuart_ServiceUUID[0] = user_data.service.main_service[1];
		bleuart_ServiceUUID[1] = user_data.service.main_service[0];

		bleuart_TxCharUUID[0] = user_data.service.notify[1];
		bleuart_TxCharUUID[1] = user_data.service.notify[0];

		bleuart_RxCharUUID[0] = user_data.service.wr[1];
		bleuart_RxCharUUID[1] = user_data.service.wr[0];

		bleuart_AT_UUID[0] = user_data.service.at[1];
		bleuart_AT_UUID[1] = user_data.service.at[0];

		blemulti_ServiceUUID[0] = user_data.service.main_service[1];
		blemulti_ServiceUUID[1] = user_data.service.main_service[0];

		blemulti_TxCharUUID[0] = user_data.service.notify[1];
		blemulti_TxCharUUID[1] = user_data.service.notify[0];

		blemulti_RxCharUUID[0] = user_data.service.wr[1];
		blemulti_RxCharUUID[1] = user_data.service.wr[0];
	}
	else if(user_data.service.flag == 1)
	{
		bleuart_Service.len = ATT_UUID_SIZE;
		masterLinkUUIDLen = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		for(int i = 0 ; i < 16 ; i ++)
		{
			bleuart_ServiceUUID[i] = user_data.service.bit128_base[15-i];
			bleuart_TxCharUUID[i] = user_data.service.bit128_base[15-i];
			bleuart_RxCharUUID[i] = user_data.service.bit128_base[15-i];
			bleuart_AT_UUID[i] = user_data.service.bit128_base[15-i];

			blemulti_ServiceUUID[i] = user_data.service.bit128_base[15-i];//link
			blemulti_TxCharUUID[i] =  user_data.service.bit128_base[15-i];//link
			blemulti_RxCharUUID[i] = user_data.service.bit128_base[15-i];//link
		}
		bleuart_ServiceUUID[12] = user_data.service.main_service[1];
		bleuart_ServiceUUID[13] = user_data.service.main_service[0];

		bleuart_TxCharUUID[12] = user_data.service.notify[1];
		bleuart_TxCharUUID[13] = user_data.service.notify[0];

		bleuart_RxCharUUID[12] = user_data.service.wr[1];
		bleuart_RxCharUUID[13] = user_data.service.wr[0];

		bleuart_AT_UUID[12] = user_data.service.at[1];
		bleuart_AT_UUID[13] = user_data.service.at[0];

		blemulti_ServiceUUID[12] = user_data.service.main_service[1]; //link
		blemulti_ServiceUUID[13] = user_data.service.main_service[0];//link

		blemulti_TxCharUUID[12] = user_data.service.notify[1];//link
		blemulti_TxCharUUID[13] = user_data.service.notify[0];//link

		blemulti_RxCharUUID[12] = user_data.service.wr[1];//link
		blemulti_RxCharUUID[13] = user_data.service.wr[0];//link
	}
	bleuart_AddService();
}

void ble_set_custom_serviceUUID(uint8 uuid_type, ble_service_t uuid)
{

	if(uuid_type == ATT_BT_UUID_SIZE )
	{
		uuid.flag = 0;
		bleuart_Service.len = ATT_BT_UUID_SIZE;
		masterLinkUUIDLen = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].type.len = ATT_BT_UUID_SIZE;
		bleuart_ServiceUUID[0] = uuid.main_service[1];
		bleuart_ServiceUUID[1] = uuid.main_service[0];

		bleuart_TxCharUUID[0] = uuid.notify[1];
		bleuart_TxCharUUID[1] = uuid.notify[0];

		bleuart_RxCharUUID[0] = uuid.wr[1];
		bleuart_RxCharUUID[1] = uuid.wr[0];

		bleuart_AT_UUID[0] = uuid.at[1];
		bleuart_AT_UUID[1] = uuid.at[0];

		blemulti_ServiceUUID[0] = uuid.main_service[1];
		blemulti_ServiceUUID[1] = uuid.main_service[0];

		blemulti_TxCharUUID[0] = uuid.notify[1];
		blemulti_TxCharUUID[1] = uuid.notify[0];

		blemulti_RxCharUUID[0] = uuid.wr[1];
		blemulti_RxCharUUID[1] = uuid.wr[0];

		osal_memcpy(&user_data.service.flag, &uuid.flag, 1);
		osal_memcpy(user_data.service.main_service, uuid.main_service, 2);
		osal_memcpy(user_data.service.notify, uuid.notify, 2);
		osal_memcpy(user_data.service.wr, uuid.wr, 2);
		osal_memcpy(user_data.service.at, uuid.at, 2);
		user_data_save();
	}
	else if(uuid_type == ATT_UUID_SIZE)
	{
		uuid.flag = 1;
		bleuart_Service.len = ATT_UUID_SIZE;
		masterLinkUUIDLen = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].type.len = ATT_UUID_SIZE;
		for(int i = 0 ; i < 16 ; i ++)
		{
			bleuart_ServiceUUID[i] = uuid.bit128_base[15-i];
			bleuart_TxCharUUID[i] = uuid.bit128_base[15-i];
			bleuart_RxCharUUID[i] = uuid.bit128_base[15-i];
			bleuart_AT_UUID[i] = uuid.bit128_base[15-i];

			blemulti_ServiceUUID[i] = uuid.bit128_base[15-i];//link
			blemulti_TxCharUUID[i] =  uuid.bit128_base[15-i];//link
			blemulti_RxCharUUID[i] = uuid.bit128_base[15-i];//link
		}
		bleuart_ServiceUUID[12] = uuid.main_service[1];
		bleuart_ServiceUUID[13] = uuid.main_service[0];

		bleuart_TxCharUUID[12] = uuid.notify[1];
		bleuart_TxCharUUID[13] = uuid.notify[0];

		bleuart_RxCharUUID[12] = uuid.wr[1];
		bleuart_RxCharUUID[13] = uuid.wr[0];

		bleuart_AT_UUID[12] = uuid.at[1];
		bleuart_AT_UUID[13] = uuid.at[0];

		blemulti_ServiceUUID[12] = uuid.main_service[1]; //link
		blemulti_ServiceUUID[13] = uuid.main_service[0];//link

		blemulti_TxCharUUID[12] = uuid.notify[1];//link
		blemulti_TxCharUUID[13] = uuid.notify[0];//link

		blemulti_RxCharUUID[12] = uuid.wr[1];//link
		blemulti_RxCharUUID[13] = uuid.wr[0];//link

		osal_memcpy(&user_data.service.flag, &uuid.flag, 1);
		osal_memcpy(user_data.service.main_service, uuid.main_service, 2);
		osal_memcpy(user_data.service.notify, uuid.notify, 2);
		osal_memcpy(user_data.service.wr, uuid.wr, 2);
		osal_memcpy(user_data.service.at, uuid.at, 2);
		osal_memcpy(user_data.service.bit128_base, uuid.bit128_base, 16);
		user_data_save();
	}

}
void ble_get_custom_serviceUUID(ble_service_t *uuid)
{
	//if(flag == 0)
	LOG("user_data.service.flag %d\n",user_data.service.flag);
	if(user_data.service.flag == 0)
	{
		uuid->flag = user_data.service.flag;
		uuid->main_service[0] = bleuart_ServiceUUID[1];
		uuid->main_service[1] = bleuart_ServiceUUID[0];

		uuid->notify[0] = bleuart_TxCharUUID[1];
		uuid->notify[1] = bleuart_TxCharUUID[0];

		uuid->wr[0] = bleuart_RxCharUUID[1];
		uuid->wr[1] = bleuart_RxCharUUID[0];

		uuid->at[0] = bleuart_AT_UUID[1];
		uuid->at[1] = bleuart_AT_UUID[0];

	}
	//else if(flag == 1)
	else if(user_data.service.flag == 1)
	{
		uuid->flag = user_data.service.flag;
		uuid->main_service[0] = bleuart_ServiceUUID[13];
		uuid->main_service[1] = bleuart_ServiceUUID[12];

		uuid->notify[0] = bleuart_TxCharUUID[13];
		uuid->notify[1] = bleuart_TxCharUUID[12];

		uuid->wr[0] = bleuart_RxCharUUID[13];
		uuid->wr[1] = bleuart_RxCharUUID[12];

		uuid->at[0] = bleuart_AT_UUID[13];
		uuid->at[1] = bleuart_AT_UUID[12];

		osal_memcpy(uuid->bit128_base, user_data.service.bit128_base, 16);

	}

}

/**
 * @fn      bleuart_DeleteService
 * @brief   Peripheral initialization
 * @param   cb
 * @return  none
 */
bStatus_t bleuart_DeleteService(void)
{
	uint8 status = SUCCESS;
	
	status = GATTServApp_DeregisterService(GATT_SERVICE_HANDLE(bleuart_ProfileAttrTbl),NULL);

	return ( status );
}

/**
 * @fn      bleuart_WriteAttrCB
 * @brief   
 * @param   cb
 * @return  none
 */
static bStatus_t bleuart_WriteAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
									  uint8 *pValue, uint16 len, uint16 offset )
{
    uint8_t index;
	static uint8_t last_index = 0xff;
    bStatus_t status = SUCCESS;
	
    //uint8 notifyApp = 0xFF;
    // If attribute permissions require authorization to write, return error
    if ( gattPermitAuthorWrite( pAttr->permissions ) )
    {
        // Insufficient authorization
        return ( ATT_ERR_INSUFFICIENT_AUTHOR );
    }
	
    if ( pAttr->type.len == ATT_BT_UUID_SIZE )
    {
        // 16-bit UUID
        uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);
        if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
        {
            status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
                                           offset, GATT_CLIENT_CFG_NOTIFY );
            if ( status == SUCCESS)
            {
                index = findConnectIndexByConnectionHandle(LL_ROLE_SLAVE, connHandle);
                if(index < g_masterMaxNum)
                {
                    uint16 charCfg = BUILD_UINT16( pValue[0], pValue[1] );
                    LOG("conn:%d vlue:%d\r\n", connHandle, charCfg);
                    if(charCfg != GATT_CFG_NO_OPERATION)
                    {
                        masterDevInfo[index].ConnectionActive = 1;
                    }
                    else
                    {
                        masterDevInfo[index].ConnectionActive = 0;
                    }
                }
            }
        }
    }
    if(pAttr->handle == bleuart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].handle)
    {
		#if 1
		uint8_t ret = 0;
		//attMsg_t sendMsg;
        LOG("master data len:%d\r\n", len);
        //for(int i=0; i<len; i++)
        {
        //   LOG("%02x ", pValue[i]);
        }
        //LOG("\r\n");
		uint8_t temp_mode = ble_get_at_mode();
		index = findConnectIndexByConnectionHandle(LL_ROLE_SLAVE, connHandle);
		osal_memcpy(sendMsg.writeReq.value, pValue,len);
        sendMsg.writeReq.len = len;
		//user_data_send_by_ble(LL_ROLE_SLAVE,0,&sendMsg);
		if(temp_mode !=BLE_ONLY_SLAVE)
		{
			ret = at_bridge_deal(AT_MASTER,index,&sendMsg);
			//LOG("ret %d\n",ret);
		}
		else
		{
			ret = AT_NULL_BRIDGE;//单从机模式下，桥接无效
		}
		
		
		if(ret == AT_NULL_BRIDGE)//桥接不存在
		{
			if(index != last_index)//方向改变了，需要输出AT命令指示
			{
				last_index = index;
				osal_memcpy(at_data.ble_data_fifo, pValue, len);//缓存从ble端收到的数据
				at_data.ble_data_len = len;//保存长度
				at_data.ble_data_index = index;//保存数据来源
				at_data.ble_data_role = AT_MASTER;//保存数据角色
				ble_task_set(USER_TASK_START, BLE_DATA_FIFO_EVT, 10);//发起事件处理
			}
			else
			{
				while(HalUartGetTxReady(UART1) == ERR_BUSY);
				HalUartSendBuf(UART1, pValue, len);
			}
		}
		#endif
    }
	if(pAttr->handle == bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].handle)
	{
		#if 1
		index = findConnectIndexByConnectionHandle(LL_ROLE_SLAVE, connHandle);
		LOG("at service len:%d\r\n", len);
        for(int i=0; i<len; i++)
        {
            LOG("%c ", pValue[i]);
        }
        LOG("\r\n");
		at_data.data_type_index = index;
		LOG("index %d\n",index);

		if(osal_memcmp(pValue, "AT+", 3))
		{
			at_command_process(pValue,len,AT_BLE);
		}
		else if(osal_memcmp(pValue, "AT", 2))//测试命令单独出来
        {
            LOG("at_test \n");
            reply_ok(AT_BLE);

        }
		#endif
	}
    return ( status );
}

/**
 * @fn      bleuart_HandleConnStatusCB
 * @brief   
 * @param   cb
 * @return  none
 */
static void bleuart_HandleConnStatusCB ( uint16 connHandle, uint8 changeType )
{ 
	///< Make sure this is not loopback connection
	if( connHandle != LOOPBACK_CONNHANDLE )
	{
		///< Reset Client Char Config if connection has dropped
		if( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||
			( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && 
			( !linkDB_Up( connHandle ) ) ) )
		{
			GATTServApp_InitCharCfg( connHandle, bleuart_TxCCCD );
		}
	}
}

uint16_t bleuart_NotifyIsReady(uint16 connHandle)
{
	return GATTServApp_ReadCharCfg(connHandle, bleuart_TxCCCD);
}

/**
 * @fn      bleuart_Notify
 * @brief   
 * @param   cb
 * @return  none
 */
bStatus_t bleuart_Notify( uint16 connHandle, attHandleValueNoti_t *pNoti)
{
	///< If notifications enabled
	if ( bleuart_NotifyIsReady(connHandle) )
	{
		///< Set the handle
		pNoti->handle = bleuart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;

		///< Send the Indication
		return GATT_Notification( connHandle, pNoti, FALSE);
	}
	return bleIncorrectMode;
}

bStatus_t bleuart_Notify_AT (uint8_t index, attMsg_t *msg)
{
	if ( bleuart_NotifyIsReady(masterDevInfo[index].ConnectionHandle) )
    {
		uint8 status;
		
		// Set the handle
		msg->handleValueNoti.handle = bleuart_ProfileAttrTbl[RAWPASS_AT_VALUE_HANDLE].handle;
		LOG("SB%d:%d\n", index+1, msg->handleValueNoti.len);
		// Send the Indication
		status = GATT_Notification( masterDevInfo[index].ConnectionHandle, &msg->handleValueNoti, FALSE);
		
		LOG("Notify:%d\r\n", status);
		return status;
	}
	return bleIncorrectMode;
}

